//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.eResearch.WFServiceLibrary.SchedulerLogic
{
    using System;
    using System.Runtime.InteropServices;
    using V1 = TaskScheduler.V1;
    using V2 = TaskScheduler;
    
    /// <summary>
    /// 
    /// </summary>
    public sealed class TaskFolder : IDisposable
    {
        V1.ITaskScheduler v1List = null;

        /// <summary>
        /// 
        /// </summary>
        V2.ITaskFolder taskFolder = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="TaskFolder"/> class.
        /// </summary>
        /// <param name="ts">The ts.</param>
        internal TaskFolder(V1.ITaskScheduler ts)
        {
            this.v1List = ts;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TaskFolder"/> class.
        /// </summary>
        /// <param name="iFldr">The i FLDR.</param>
        internal TaskFolder(V2.ITaskFolder iFldr)
        {
            this.taskFolder = iFldr;
        }

        /// <summary>
        /// Releases all resources used by this class.
        /// </summary>
        public void Dispose()
        {
            if (this.taskFolder != null)
            {
                Marshal.ReleaseComObject(this.taskFolder);
            }

            this.v1List = null;
        }

        /// <summary>
        /// Gets the name that is used to identify the folder that contains a task.
        /// </summary>
        public string Name
        {
            get { return (this.taskFolder == null) ? @"\" : this.taskFolder.Name; }
        }

        /// <summary>
        /// Gets the path to where the folder is stored.
        /// </summary>
        public string Path
        {
            get { return (this.taskFolder == null) ? @"\" : this.taskFolder.Path; }
        }

        /// <summary>
        /// Gets a collection of all the tasks in the folder.
        /// </summary>
        public TaskCollection Tasks
        {
            get
            {
                if (this.taskFolder != null)
                {
                    return new TaskCollection(this.taskFolder.GetTasks(1));
                }

                return new TaskCollection(this.v1List);
            }
        }

        /// <summary>
        /// Registers (creates) a task in a specified location using a <see cref="TaskDefinition"/> instance to define a task.
        /// </summary>
        /// <param name="path">The task name. If this value is NULL, the task will be registered 
        /// in the root task folder and the task name will be a GUID value that is created by 
        /// the Task Scheduler service. A task name cannot begin or end with a space character. 
        /// The '.' character cannot be used to specify the current task folder and the '..' 
        /// characters cannot be used to specify the parent task folder in the path.</param>
        /// <param name="definition">The <see cref="TaskDefinition"/> of the registered task.</param>
        /// <returns>A <see cref="Task"/> instance that represents the new task.</returns>
        public Task RegisterTaskDefinition(string path, TaskDefinition definition)
        {
            return this.RegisterTaskDefinition(path, definition, TaskCreation.CreateOrUpdate, null, null, V2._TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN, null);
        }

        /// <summary>
        /// Registers the task definition.
        /// </summary>
        /// <param name="Path">The path.</param>
        /// <param name="definition">The definition.</param>
        /// <param name="createType">Type of the create.</param>
        /// <param name="UserId">The user id.</param>
        /// <param name="password">The password.</param>
        /// <param name="LogonType">Type of the logon.</param>
        /// <param name="sddl">The SDDL.</param>
        /// <returns></returns>
        public Task RegisterTaskDefinition(string Path, TaskDefinition definition, TaskCreation createType, string UserId, string password, V2._TASK_LOGON_TYPE LogonType, string sddl)
        {
            if (this.taskFolder != null)
            {
                return new Task(this.taskFolder.RegisterTaskDefinition(Path, definition.taskDefinition, (int)createType, UserId, password, LogonType, sddl));
            }

            // Adds ability to set a password for a V1 task.
            V1.TaskFlags flags = definition.v1Task.GetFlags();
            switch (LogonType)
            {
                case V2._TASK_LOGON_TYPE.TASK_LOGON_GROUP:
                case V2._TASK_LOGON_TYPE.TASK_LOGON_S4U:

                case V2._TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN:
                    flags |= (V1.TaskFlags.Interactive);
                    if (String.IsNullOrEmpty(UserId))
                        UserId = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
                    definition.v1Task.SetAccountInformation(UserId, IntPtr.Zero);
                    break;
                case V2._TASK_LOGON_TYPE.TASK_LOGON_SERVICE_ACCOUNT:
                    definition.v1Task.SetAccountInformation(String.IsNullOrEmpty(UserId) ? String.Empty : UserId, IntPtr.Zero);
                    break;
                case V2._TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD:
                    using (V1.CoTaskMemString cpwd = new V1.CoTaskMemString(password))
                        definition.v1Task.SetAccountInformation(UserId, cpwd.DangerousGetHandle());
                    flags |= V1.TaskFlags.Interactive;
                    break;
                case V2._TASK_LOGON_TYPE.TASK_LOGON_PASSWORD:
                    using (V1.CoTaskMemString cpwd = new V1.CoTaskMemString(password))
                        definition.v1Task.SetAccountInformation(UserId, cpwd.DangerousGetHandle());
                    break;
                default:
                    break;
            }
            definition.v1Task.SetFlags(flags);

            switch (createType)
            {
                case TaskCreation.Create:
                case TaskCreation.CreateOrUpdate:
                case TaskCreation.Disable:
                case TaskCreation.Update:
                    if (createType == TaskCreation.Disable)
                        definition.Settings.Enabled = false;
                    definition.V1Save(Path);
                    break;
                default:
                    break;
            }
            return new Task(definition.v1Task);
        }

        /// <summary>
        /// Deletes a task from the folder.
        /// </summary>
        /// <param name="taskName">The name of the task that is specified when the task was registered. The '.' character cannot be used to specify the current task folder and the '..' characters cannot be used to specify the parent task folder in the path.</param>
        public void DeleteTask(string taskName)
        {
            if (this.taskFolder != null)
            {
                this.taskFolder.DeleteTask(taskName, 0);
            }
            else
            {
                v1List.Delete(taskName);
            }
        }
    }
}
